use io::BufReader as Reader;
use std::fs::File;
use std::io::{self, BufRead};

type Date = (usize, usize, usize);

pub fn time_info(time: &str) -> String {
    let date = parse_time(time);
    let left_days = get_day(date.0) - nth_day(date);
    let nth_week = get_nth_week(date);
    let nearest_sf = get_nearest_spring_festival(date);
    let days_to_sf = if nearest_sf.0 == date.0 {
        nth_day(nearest_sf) - nth_day(date) - 1
    } else {
        // in next year
        left_days + nth_day(nearest_sf) - 1
    };
    format!("{},{},{}", nth_week, left_days, days_to_sf)
}

fn get_nearest_spring_festival(date: Date) -> Date {
    let cur_sf = get_spring_festival(date.0);
    let next_sf = get_spring_festival(date.0 + 1);
    let nearest_sf = if date.0 == cur_sf.0 && nth_day(date) < nth_day(cur_sf) {
        cur_sf
    } else {
        next_sf
    };
    nearest_sf
}

fn parse_time(time: &str) -> Date {
    let mut iter = time.split('-');
    let year = iter.next().unwrap().parse::<usize>().unwrap();
    let month = iter.next().unwrap().parse::<usize>().unwrap();
    let day = iter.next().unwrap().parse::<usize>().unwrap();
    (year, month, day)
}

fn judge_leap(year: usize) -> usize {
    if (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) {
        1
    } else {
        0
    }
}

fn get_day(year: usize) -> usize {
    if judge_leap(year) == 1 {
        366
    } else {
        365
    }
}

fn nth_day(date: Date) -> usize {
    let (year, month, day) = date;
    let is_leap = judge_leap(year);
    let days = vec![
        vec![0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
        vec![0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
    ];
    let mut ans: usize = 0;
    ans = ans + day;
    for i in 1..month {
        ans = ans + days[is_leap as usize][i as usize];
    }
    return ans;
}

// from Internet
fn get_spring_festival(year: usize) -> Date {
    let file = File::open("spring_festival.txt").unwrap();
    let reader = Reader::new(file);
    let mut spring_festival: Vec<Date> = Vec::new();
    for line in reader.lines() {
        let line = line.unwrap();
        let mut iter = line.split(' ');
        let year = iter.next().unwrap().parse::<usize>().unwrap();
        let month = iter.next().unwrap().parse::<usize>().unwrap();
        let day = iter.next().unwrap().parse::<usize>().unwrap();
        spring_festival.push((year, month, day));
    }

    let ans = (year, 1, 1);
    if year < 2000 || year > 2050 {
        ans
    } else {
        let ans = spring_festival[year - 2000];
        (ans.0, ans.1, ans.2)
    }
}

// from Internet
fn get_nth_week(date: Date) -> usize {
    let res = nth_day(date) / 7 + 1;
    if date.0 < 2000 || date.0 > 2050 {
        return res;
    }
    // find the first thursday of the first week
    let first_day = get_first_day(date.0);
    let first_thursday: Date = if first_day <= 4 {
        (date.0, 1, 4 - first_day + 1)
    } else {
        (date.0, 1, 11 - first_day + 1)
    };
    let sunday_before_first_thursday: isize = first_thursday.2 as isize - 4;
    let days_passed = nth_day(date) as isize - sunday_before_first_thursday;
    let mut ans: usize = days_passed as usize / 7;
    if days_passed % 7 != 0 {
        ans = (ans + 1) as usize;
    } else {
        ans = ans as usize;
    }
    ans % 52
}

fn get_first_day(year: usize) -> usize {
    // We know that 1st Jan 2000 is Saturday
    // Find the day of 1st Jan of year
    let base_year = 2000;
    let base_day = 6;
    let mut days: isize = 0;
    if year > base_year {
        for i in base_year..year {
            days += get_day(i) as isize;
        }
    } else {
        for i in year..base_year {
            days -= get_day(i) as isize;
        }
    }
    let day = (days + base_day) % 7;
    let day = if day < 0 {
        ((day % 7) + 7) as usize
    } else {
        day as usize
    };
    if day == 0 {
        7
    } else {
        day
    }
}

// unit test for get_first_day
#[test]
fn test_first_day() {
    const FIRST_DAY: [(usize, usize); 53] = [
        (1998, 4),
        (1999, 5),
        (2000, 6),
        (2001, 1),
        (2002, 2),
        (2003, 3),
        (2004, 4),
        (2005, 6),
        (2006, 7),
        (2007, 1),
        (2008, 2),
        (2009, 4),
        (2010, 5),
        (2011, 6),
        (2012, 7),
        (2013, 2),
        (2014, 3),
        (2015, 4),
        (2016, 5),
        (2017, 7),
        (2018, 1),
        (2019, 2),
        (2020, 3),
        (2021, 5),
        (2022, 6),
        (2023, 7),
        (2024, 1),
        (2025, 3),
        (2026, 4),
        (2027, 5),
        (2028, 6),
        (2029, 1),
        (2030, 2),
        (2031, 3),
        (2032, 4),
        (2033, 6),
        (2034, 7),
        (2035, 1),
        (2036, 2),
        (2037, 4),
        (2038, 5),
        (2039, 6),
        (2040, 7),
        (2041, 2),
        (2042, 3),
        (2043, 4),
        (2044, 5),
        (2045, 7),
        (2046, 1),
        (2047, 2),
        (2048, 3),
        (2049, 5),
        (2050, 6),
    ];
    let s = 1998;
    let e = 2050;
    for i in s..e {
        assert_eq!(get_first_day(i), FIRST_DAY[i - s].1);
    }
}
